/**
  ******************************************************************************
  * @author     Chris
  * @since      2024/6/13 14:24
  *
  * @file       pd_timer_pwm.c
  * @brief      TimerPWM peripheral driver.
  *
  * @note       This file contains the peripheral driver for the TimerPWM.
  *
  * @warning    None.
  ******************************************************************************
  * Change Logs:
  *   Date          Author       Notes
  *   2024/6/13     Chris        the first version
  *
  ******************************************************************************
  */

#include <stm32f4xx_ll_tim.h>
#include "pd_timer_pwm.h"

static void TimerPWM_init(TimerPWM *this) {
    if (LL_TIM_IsEnabledCounter(this->timer->TIMx)) {
        // Update Timer channel if Timer is running.
        this->timerOC->init(this->timerOC);
        return;
    }

    // Timer Base Unit
    this->timer->init(this->timer);

    // Set Internal Clock Source
    LL_TIM_SetClockSource(this->timer->TIMx, LL_TIM_CLOCKSOURCE_INTERNAL);

    // Set Timer Output Compare Unit
    this->timerOC->init(this->timerOC);

    LL_TIM_EnableCounter(this->timer->TIMx);
}


/**
 * @brief   修改定时器 4 的 PWM 占空比（通过改变 CCR 的值）
 *
 * @note    PWM 占空比的计算方式：
 *          PWM 占空比 = CCR / (ARR + 1)
 * @param   val 要设置的 CCR 的值
 * @param   channel This parameter can be one of the following values:
 *          @arg @ref LL_TIM_CHANNEL_CH1
 *          @arg @ref LL_TIM_CHANNEL_CH2
 *          @arg @ref LL_TIM_CHANNEL_CH3
 *          @arg @ref LL_TIM_CHANNEL_CH4
 *          @arg @ref LL_TIM_CHANNEL_CH5
 *          @arg @ref LL_TIM_CHANNEL_CH6
 * @retval  无
 */
static void TimerPWM_setDuty(TimerPWM *this, const uint32_t channel, const uint32_t val) {
    switch (channel) {
        case LL_TIM_CHANNEL_CH1:
            LL_TIM_OC_SetCompareCH1(this->timer->TIMx, val);
            break;
        case LL_TIM_CHANNEL_CH2:
            LL_TIM_OC_SetCompareCH2(this->timer->TIMx, val);
            break;
        case LL_TIM_CHANNEL_CH3:
            LL_TIM_OC_SetCompareCH3(this->timer->TIMx, val);
            break;
        case LL_TIM_CHANNEL_CH4:
            LL_TIM_OC_SetCompareCH4(this->timer->TIMx, val);
            break;
        default:
            break;
    }
}

static TimerPWM *build(Timer *timer, TimerOC *timerOC) {
    TimerPWM *timerPWM = malloc(sizeof(TimerPWM));

    Driver_add(timerPWM, GEN_PERM);

    timerPWM->timer      = timer;
    timerPWM->timerOC    = timerOC;
    timerPWM->init       = TimerPWM_init;
    timerPWM->setPWMDuty = &TimerPWM_setDuty;

    return timerPWM;
}

const struct TimerPWMClass TimerPWMBuilder = {.build = &build};